SPDX-FileCopyrightText: 2019 Arnaud Froment & Thomas Paquot SPDX-FileCopyrightText: 2024 AlICe laboratory https://alicelab.be
SPDX-License-Identifier: GPL-3.0-or-later
-- coding:Utf8 --
Imaginary Landscape Nr.4 - John Cage # Authors: Arnaud Froment & Thomas Paquot # Date: 24/01/2020 # Blender version: 2.80 # OS: MacOS Catalina & Windows 10 #
import of the external functions
import bpy
import random
from math import piactivation of boolean tools in blender settings
import addon_utils
addon_utils.enable("object_boolean_tools")delete neg cube at every run
def reset():
    bpy.ops.object.select_all(action="DESELECT")
    bpy.data.objects["negative"].select_set(True)
    bpy.ops.object.delete()
PARAMETERS = {"scale_min": 10, "scale_max": 25, "patterns": 6, "radios": 12}
COIN_TOSSES = {"heads": 0, "tails": 0}
OBJECTS = {
    "cubes": [0, 0],
    "tetrahedrons": [0, 0],
    "icosahedrons": [0, 0],
}  # index 0 = build; index 1 = unbuildCoin toss 3 times print(“You flipped heads”, total_heads, “times”,”and tails”, total_tails, “times”)
def cointoss():
    total_heads = 0
    total_tails = 0
    for _ in range(3):  # Coin toss 3 times to create a line 0 or 1 see futher down
        coin = random.randint(1, 2)
        if coin == 1:  # heads
            total_heads += 1
        elif coin == 2:  # tails
            total_tails += 1    if (total_heads == 3 and total_tails == 0) or (
        total_heads == 2 and total_tails == 1
    ):
        hexlist.append(0)  # adds a 0 to hexlist
        print("🀰🀰🀰🀰    🀰🀰🀰🀰")  # Line print if 0
    elif (total_heads == 1 and total_tails == 2) or (
        total_heads == 0 and total_tails == 3
    ):
        hexlist.append(1)  # adds a 1 to hexlist
        print("🀰🀰🀰🀰🀰🀰🀰🀰🀰🀰🀰🀰")  # line print if 1
    COIN_TOSSES["heads"] += total_heads
    COIN_TOSSES["tails"] += total_tailsempty hexagram
hexlist = []clear the hexagram and load it again
def hexagram():
    hexlist.clear()
    for _ in range(6):  # 6 x 3 coin tosses for an hexagram to be created
        cointoss()print(hexlist,’\n’)
    print()iChing List of 64 Hexagrams
ichinglist = [
    [1, 1, 1, 1, 1, 1],
    [0, 0, 0, 0, 0, 0],
    [0, 1, 0, 0, 0, 1],
    [1, 0, 0, 0, 1, 0],
    [0, 1, 0, 1, 1, 1],
    [1, 1, 1, 0, 1, 0],
    [0, 0, 0, 0, 1, 0],
    [0, 1, 0, 0, 0, 0],
    [1, 1, 0, 1, 1, 1],
    [1, 1, 1, 0, 1, 1],
    [0, 0, 0, 1, 1, 1],
    [1, 1, 1, 0, 0, 0],
    [1, 1, 1, 1, 0, 1],
    [1, 0, 1, 1, 1, 1],
    [0, 0, 0, 1, 0, 0],
    [0, 0, 1, 0, 0, 0],
    [0, 1, 1, 0, 0, 1],
    [1, 0, 0, 1, 1, 0],
    [0, 0, 0, 0, 1, 1],
    [1, 1, 0, 0, 0, 0],
    [1, 0, 1, 0, 0, 1],
    [1, 0, 0, 1, 0, 1],
    [1, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 1],
    [1, 1, 1, 0, 0, 1],
    [1, 0, 0, 1, 1, 1],
    [1, 0, 0, 0, 0, 1],
    [0, 1, 1, 1, 1, 0],
    [0, 1, 0, 0, 1, 0],
    [1, 0, 1, 1, 0, 1],
    [0, 1, 1, 1, 0, 0],
    [0, 0, 1, 1, 1, 0],
    [1, 1, 1, 1, 0, 0],
    [0, 0, 1, 1, 1, 1],
    [0, 0, 0, 1, 0, 1],
    [1, 0, 1, 0, 0, 0],
    [1, 1, 0, 1, 0, 1],
    [1, 0, 1, 0, 1, 1],
    [0, 1, 0, 1, 0, 0],
    [0, 0, 1, 0, 1, 0],
    [1, 0, 0, 0, 1, 1],
    [1, 1, 0, 0, 0, 1],
    [0, 1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1, 0],
    [0, 1, 1, 0, 0, 0],
    [0, 0, 0, 1, 1, 0],
    [0, 1, 1, 0, 1, 0],
    [0, 1, 0, 1, 1, 0],
    [0, 1, 1, 1, 0, 1],
    [1, 0, 1, 1, 1, 0],
    [0, 0, 1, 0, 0, 1],
    [1, 0, 0, 1, 0, 0],
    [1, 1, 0, 1, 0, 0],
    [0, 0, 1, 0, 1, 1],
    [0, 0, 1, 1, 0, 1],
    [1, 0, 1, 1, 0, 0],
    [1, 1, 0, 1, 1, 0],
    [0, 1, 1, 0, 1, 1],
    [1, 1, 0, 0, 1, 0],
    [0, 1, 0, 0, 1, 1],
    [1, 1, 0, 0, 1, 1],
    [0, 0, 1, 1, 0, 0],
    [0, 1, 0, 1, 0, 1],
    [1, 0, 1, 0, 1, 0],
]Defines the parameters (64 values per parameters = I CHING) at each structural point (random)
def make_random():
    hexagram()
    x = (
        ichinglist.index(hexlist) + 1
    )  # Duration X, #indexing where in the list + 1 the hexagram is situated to randomize a number
    hexagram()
    y = ichinglist.index(hexlist) + 1  # Dynamic Y
    hexagram()
    z = ichinglist.index(hexlist) + 1  # Frequency Z
    hexagram()
    s = ichinglist.index(hexlist) + 1  # Scale
    hexagram()
    r = (
        ichinglist.index(hexlist) + 1
    ) * 5.625  # Rotation, #5.625 is the amount of times 64 can fit in 360print(x,y,z,s,r)
    axis = random.choice(["x", "y", "z"])
    if eval(axis) % 2 != 0:  # Uneven elements are 0
        if axis == "x":
            x = 0
        elif axis == "y":
            y = 0
        elif axis == "z":
            z = 0
    if s not in range(
        PARAMETERS["scale_min"], PARAMETERS["scale_max"]
    ):  # Choose a range in the 64 elements
        s = 0
    return x, y, z, s, r  # Giving the info back to the make_random function when calleddefine the keywords of the basic forms
addcube = bpy.ops.mesh.primitive_cube_add
addtetrahedron = bpy.ops.mesh.primitive_cone_add
addicosahedron = bpy.ops.mesh.primitive_ico_sphere_addDefine the pattern
def pattern(loop):  # builds objects if no 0 in iching
    for _ in range(loop):
        x, y, z, s, r = (
            make_random()
        )  ##section for the cube, 8 vertices #return the x y z s r values
        if 0 not in {x, y, z, s, r}:  # if value is 0
            addcube(
                size=s,
                location=(x, y, z),
                rotation=((r * pi / 180), (r * pi / 180), (r * pi / 180)),
            )
            OBJECTS["cubes"][0] += 1
        else:
            pass  # counter
            OBJECTS["cubes"][1] += 1
        x, y, z, s, r = make_random()  # section for the tetrahedron, 4 vertices
        if 0 not in {x, y, z, s, r}:
            addtetrahedron(
                radius1=s,
                radius2=0,
                depth=s * 2,
                vertices=3,
                location=(x, y, z),
                rotation=((r * pi / 180), (r * pi / 180), (r * pi / 180)),
            )
            OBJECTS["tetrahedrons"][0] += 1
        else:
            pass
            OBJECTS["tetrahedrons"][1] += 1
        x, y, z, s, r = make_random()  # section for the icosahedron, 12 vertices
        if 0 not in {x, y, z, s, r}:
            addicosahedron(
                subdivisions=1,
                radius=s,
                location=(x, y, z),
                rotation=((r * pi / 180), (r * pi / 180), (r * pi / 180)),
            )
            OBJECTS["icosahedrons"][0] += 1
        else:
            pass
            OBJECTS["icosahedrons"][1] += 1how much radios are chosen
def radio(loop):
    for _ in range(loop):
        pattern(PARAMETERS["patterns"])call a new score
def score():
    radio(PARAMETERS["radios"])shows info of the score created
def scoreinfo():
    print("Total coin tosses:", COIN_TOSSES["heads"] + COIN_TOSSES["tails"])
    print()
    print("Total build cubes:", OBJECTS["cubes"][0])
    print("Total unbuild cubes:", OBJECTS["cubes"][1])
    print()
    print("Total build tetrahedrons:", OBJECTS["tetrahedrons"][0])
    print("Total unbuild tetrahedrons:", OBJECTS["tetrahedrons"][1])
    print()
    print("Total build icosahedrons:", OBJECTS["icosahedrons"][0])
    print("Total unbuild icosahedrons:", OBJECTS["icosahedrons"][1])
    print()
    print("---------------------------")Union off all the events
def union():
    bpy.ops.object.select_all(action="SELECT")
    bpy.ops.object.booltool_auto_union()Name the Unified object ‘Positive’
def positive():
    bpy.ops.object.select_all(action="SELECT")
    bpy.context.object.name = "positive"Add the cube of 64 to 64 to create the negative afterwards
def negative():
    addcube(size=64, location=(32, 32, 32))
    bpy.context.object.name = "negative"
    negative = bpy.context.objectBoolean operation: negative(cube) - positive (objects)
def boolnegpos():
    bpy.ops.object.modifier_add(type="BOOLEAN")
    bpy.context.object.modifiers["Boolean"].operation = "DIFFERENCE"
    bpy.context.object.modifiers["Boolean"].object = bpy.data.objects["positive"]
    bpy.ops.object.modifier_apply(apply_as="DATA", modifier="Boolean")def delpos():
    bpy.ops.object.select_all(action="DESELECT")
    bpy.data.objects["positive"].select_set(True)
    bpy.ops.object.delete()rescale the final form to a 10x10 square
def rescale():
    bpy.ops.object.select_all(action="SELECT")
    bpy.ops.transform.resize(value=(0.15625, 0.15625, 0.15625))
    bpy.context.object.location[0] = 5
    bpy.context.object.location[1] = 5
    bpy.context.object.location[2] = 5calling the functions:
reset()
score()
scoreinfo()
union()
positive()
negative()
boolnegpos()
delpos()
rescale()